﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Summerset.Isbndb
{

    /// <summary>
    /// Represents data returned from the ISBNdb.com API.  
    /// </summary>
    /// <typeparam name="PageType">The type of pages that this response will contain.</typeparam>
    /// <typeparam name="ElementType">The type of element that the page will contain.</typeparam>
    public sealed class Response<PageType, ElementType> : 
        INotifyPropertyChanged 
        where PageType : ResponsePageBase<ElementType> 
        where ElementType : ResponseElementBase
    {

        #region Constructor 

        /// <summary>
        /// Initializes a new response from the ISBNdb API.  
        /// </summary>
        /// <param name="Request">The information that will be requested from the API.</param>
        /// <param name="Owner">The <see cref="Isbndb"/> instance that will own this response and will determine how this request is executed.</param>
        public Response(RequestBase Request, Isbndb Owner)
        {

            // Simply set these two reference properties. 
            this.Owner                  = Owner;
            this.Request                = Request;

            // This property is used by the Pages property.  It needs to reflect the Owner's PageLoadBehavior when this instance was initialized and cannot change thereafter.
            this.PageLoadingBehavior    = Owner.PageLoadingBehavior; 


            // When we initialize the Pages collection, the first page will be loaded synchronously regardless of our PageLoadingBehavior
            this.Pages                      = new PagesCollection<PageType, ElementType>(this);
            this.Pages.PropertyChanged      += new PropertyChangedEventHandler(Pages_PropertyChanged);

        }

        #endregion
        #region Properties

        /// <summary>
        /// Gets the <see cref="Isbndb"/> instance that owns this response and has the necessary configuration information to execute the request.
        /// </summary>
        public Isbndb Owner { get; private set; }

        /// <summary>
        /// Gets a collection containing the pages that have been returned from the API.  
        /// Each page represents a single request that's been executed against the API.  By default
        /// these pages will not be loaded until they're requested (except the first page at index 0, 
        /// which is loaded automatically).
        /// </summary>
        public PagesCollection<PageType, ElementType> Pages { get; private set; }

        /// <summary>
        /// Gets the number of pages that contained in the Pages collection.  Depending on the page loading behavior, 
        /// some of these values may still be null.
        /// </summary>
        public int MaximumResultsCount 
        {
            get 
            {
                // The first page is always loaded on initialization.
                return Pages[0].MaximumResults;
            }
        }

        /// <summary>
        /// Gets the request that was used to generate this response.
        /// </summary>
        public RequestBase Request { get; private set; }

        /// <summary>
        /// Gets the page loading behavior.  By default the page loading behavior is 'SyncLoadOnRequest'
        /// which is recommended.  
        /// </summary>
        /// <remarks>
        /// Certain results can generate an enormous amount of response data
        /// if all the pages were loaded at once (and therefore eat up all of your allowed requests
        /// in a single request). SyncLoadOnRequest will only generate the first page of results,
        /// and then additional pages of results will be loaded automatically as they are requested by client code.
        /// </remarks>
        public PageLoadingBehavior PageLoadingBehavior { get; private set; }

        #endregion
        #region Methods + Event Handlers

        void Pages_PropertyChanged(object sender, PropertyChangedEventArgs e) 
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs("Pages"));
        }

        #endregion
        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
